<?php
// 微信用户
// +---------------+--------------+------+-----+---------+----------------+
// | Field         | Type         | Null | Key | Default | Extra          |
// +---------------+--------------+------+-----+---------+----------------+
// | id            | int(11)      | NO   | PRI | NULL    | auto_increment |
// | app_id        | int(11)      | YES  |     | 0       |                |
// | openid        | varchar(50)  | YES  |     |         |                |
// | access_token  | varchar(200) | YES  |     |         |                |
// | expired_at    | datetime     | YES  |     | NULL    |                |
// | refresh_token | varchar(200) | YES  |     |         |                |
// | scope         | varchar(50)  | YES  |     |         |                |
// | subscribe     | int(11)      | YES  |     | 0       |                |
// | nickname      | varchar(255) | YES  |     |         |                |
// | sex           | int(11)      | YES  |     | 0       |                |
// | language      | varchar(10)  | YES  |     |         |                |
// | city          | varchar(100) | YES  |     |         |                |
// | province      | varchar(100) | YES  |     |         |                |
// | country       | varchar(100) | YES  |     |         |                |
// | headimgurl    | varchar(255) | YES  |     |         |                |
// | subscribed_at | datetime     | YES  |     | NULL    |                |
// | editor_id     | int(11)      | YES  |     | 0       |                |
// | create_time   | int(11)      | YES  |     | 0       |                |
// | update_time   | int(11)      | YES  |     | 0       |                |
// +---------------+--------------+------+-----+---------+----------------+
namespace app\weixin\model;
use think\Model;
use think\Loader;
use app\weixin\model\TPWechat;
use app\weixin\model\WeixinApp;
class WeixinUser extends Model {
  /**
   * 微信授权成功后的callback保存方法
   * @Author zhanghong
   * @Date   2017-01-25
   * @param  [type]     $appid [description]
   * @return [type]            [description]
   */
  public function authCallback($appid){
    $chat = new TPWechat($appid);
    $token = $chat->getOauthAccessToken();
    // debug_echo($token, "base_info");
    if($token){
      if(strpos($token["scope"], "snsapi_userinfo") >= 0){
        $user_info = $chat->getOauthUserinfo($token["access_token"], $token["openid"]);
        if($user_info){
          $token = array_merge($token, $user_info);  
        }
      }
      //本地保存用户授权信息
      $user_data = array_merge($token, ["app_id" => $chat->weixin_app_id]);
      $this->updateOrAdd($user_data);
      // getUserinfo（user/info）和 getOauthUserinfo（sns/userinfo）不一样
      // 已关注用户调用getUserinfo方法会返回用户信息，未关注用户不会返回用户信息
      // 授权用户调用getOauthUserinfo会返回用户基本信息（不包含是否关注公众号）
      $this->getUserinfo($token["openid"]);
      $result = $user_data;
    }else{
      $result = ["errcode" => 90001, "errmsg" => "获取用户信息失败"];
    }
    return $result;
  }

  /**
  * 刷新用户授权token
  * @param $openid string 用户微信授权key
  * @return array
  * @return array {openid,nickname,sex,province,city,country,headimgurl,privilege,[unionid]}
  */
  public function getOauthUserinfo($openid){
    $user = $this->findUserByOpenid($openid);
    if(empty($user)){
      $result = ["errcode" => 90000, "errmsg" => "授权用户不存在"];
    }else{
      $chat = new TPWechat($user["app_id"]);
      $expired_at = strtotime($user["expired_at"]);
      if(time() > $expired_at){
        $token_info = $this->getOauthRefreshToken($user);
        if(isset($token_info["access_token"])){
          $access_token = $token_info["access_token"];
        }else{
          // 刷新用户的access_token失败
          return $token_info;
        }
      }else{
        $access_token = $user["access_token"];
      }

      $user_info = $chat->getOauthUserinfo($access_token, $openid);
      if($user_info){
        $this->updateOrAdd($user_info, $user["id"]);
        $result = $user_info; 
      }else{
        $result = ["errcode" => 90001, "errmsg" => "获取用户信息失败"];
      }

      $this->updateSessionAppUser($user["id"]);
    }
    return $result;
  }

  /**
  * 获取关注者详细信息
  * @param $openid string 用户微信授权key
  * @return array
  * @return array {subscribe,openid,nickname,sex,city,province,country,language,headimgurl,subscribe_time,[unionid]}
  */
  public function getUserinfo($openid){
    $user = $this->findUserByOpenid($openid);
    if(empty($user)){
      $result = ["errcode" => 90000, "errmsg" => "授权用户不存在"];
    }else{
      $chat = new TPWechat($user["app_id"]);
      $user_info = $chat->getUserInfo($openid);
      if($user_info){
        $this->updateOrAdd($user_info, $user["id"]);
        $result = $user_info;
      }else{
        $result = ["errcode" => 90001, "errmsg" => "获取用户信息失败"];
      }
    }
    return $result;
  }

  /**
  * 保存授权用户信息
  * @param data array 用户授权信息
  * @param id integer 用户ID
  * @return array
  */
  private function updateOrAdd($data, $id = 0){
    $user_id = 0;
    $result = ["status" => false, "msg" => "添加或更新用户失败"];
    if(empty($data["openid"])){
      $result["msg"] = "openid不能为空";
    }else{
      if(isset($data["expires_in"])){
        $current_time = time();
        $expired_time = $current_time + intval($data["expires_in"]);
        $data["expired_at"] = format_show_time($expired_time);
      }

      if(isset($data["subscribe_time"])){
        $subscribe_time = intval($data["subscribe_time"]);
        $data["subscribed_at"] = format_show_time($subscribe_time);
      }

      if(isset($data["unionid"])){
        $data["unionid"] = json_encode($data["unionid"]);
      }

      if(isset($data["scope"])){
        if(strpos($data["scope"], "snsapi_userinfo")){
          $data["scope"] = "snsapi_userinfo";
        }else{
          $data["scope"] = "snsapi_base";
        }
      }

      $validate = Loader::validate("WeixinUser");
      if($validate->check($data)){
        if(empty($id)){
          $this->where("openid", $data["openid"]);
        }else{
          $this->where("id", $id);
        }
        $user = $this->find();

        $this->allowField(true);
        if(empty($user)){
          $this->save($data);
          $user_id = $this->id;
          $result = ["status" => true, "msg" => "保存新用户成功"];
        }else{
          $user_id = $user["id"];
          $data["id"] = $user["id"];
          $this->isUpdate(true)->save($data);
          $result = ["status" => true, "msg" => "更新用户信息成功"];
        }
      }else{
        $result["msg"] = $validate->getError();
      }
    }

    if($user_id){
      $this->updateSessionAppUser($user_id);
    }
    return $result;
  }

  /**
  * 通过openid查找用户
  * @param $id integer 用户ID
  * @return bool
  */
  private function findUserByOpenid($openid){
    $user = session_weixin_user($openid);
    if(empty($user)){
      $user = $this->where("openid", $openid)->find();
    }
    return $user;
  }

  /**
  * 把用户授权信息保存到session里
  * @param $id integer 用户ID
  * @return bool
  */
  private function getOauthRefreshToken($user){
    $chat = new TPWechat($user["app_id"]);
    $token_info = $chat->getOauthRefreshToken($user["refresh_token"]);
    // var_dump($token_info, "token info");
    if($token_info){
      $this->updateOrAdd($token_info, $user["id"]);
      $result = $token_info;
    }else{
      $result = ["errcode" => 90101, "errmsg" => "刷新用户授权token失败"];
    }
    return $result;
  }

  /**
  * 把用户授权信息保存到session里
  * @param $id integer 用户ID
  * @return bool
  */
  private function updateSessionAppUser($id){
    if(is_numeric($id)){
      $user = $this->where("id", $id)->find();
      if($user){
        session_weixin_user($user["openid"], $user);
        return true;
      }
    }
    
    return false;
  }
}